module SDLBridge.SDLTexture;
private import SDL;
private import SDL_mixer;
private import opengl;
private import openglu;
private import SDLBridge.SDLGraphics;
private import Graphics.IGraphics;
private import Graphics.ZSorter;
private import System.Console;

//private import std.math;
private import std.string;

class SDLTexture : ITexture{
	private Rectangle _clip;
	private int		  _index = 0;
	private int _width = 256 , _height = 256;
	private SDLTexture _texture;
	private bool _share;
	private string _file;
	private SDL_Surface* _surface;
	private uint _id = 0;
	private string _key = null;
	public uint id(){return _id;}
	public string key() {
		if ( _key is null || _key.length == 0 ) {
			return "";
		}
		return _key;
	} //
	
	private this( ){
	} //
	
	private this( string fileName ){
		SDL_Surface* s = loadBitmap( fileName );
		create( s );
	} //

	private this( string fileName , Color key ){
		SDL_Surface* s = loadBitmap( fileName );
		s = setColorKey( s , key );
		create( s );
	} //

	private this( string fileName , int keyX , int keyY ){
		SDL_Surface* s = loadBitmap( fileName );
		s = setColorKey( s , getColor( s , keyX , keyY ) );
		create( s );
	} //

	private ITexture getClone(){
		SDLTexture tex = new SDLTexture();
		tex._surface = _surface;
		tex._width   = _surface.w;
		tex._height  = _surface.h;
		tex._id		 = _id;
		tex._clip	 = _clip.clone();
		tex._key	 = _key;
		return tex;
	} //

	public ~this(){
		if ( _key is null || _key.length == 0 ) {
			Console.writeln("DELETE Texture ID:%d" , _id );
			glDeleteTextures(1 , &_id);
			SDL_FreeSurface(_surface);
		} else {
			SDLTexture.dispose( _key );
		}
	} //



	public int width(){
		return _width;
	} //
	
	public int height(){
		return _height;
	} //

	public void setFrameSize( int w , int h  , int index = 0 ){
		if ( w <= 0 || h <= 0 ) return;
//			throw new Exeption("Framesize or Texturesize error");
		_clip.width     = w;
		_clip.height    = h;
		frameIndex = index;
	} //

	public void setFrameSize( Rectangle rect , int index = 0 ){
		setFrameSize( cast(int)rect.width , cast(int)rect.height , frameIndex);
	} //

	public void setFrameSizeDiv( int divX , int divY , int index = 0 ){
		if ( divX <= 0 || divY <= 0 ) return;
		int w = _width / divX , h = _height / divY;
		setFrameSize( w , h , frameIndex);
	} //

	public int  frameIndex(){
		return _index;
	} //

	public void frameIndex( int f ){
		if( f < 0 ) return;
		int cols = cast(int)(_width  / _clip.width);
		int rows = cast(int)(_height / _clip.height);
		int cells = cols * rows;
		f = f % cells;
		_index = f;
		_clip.x = ( f % cols ) * _clip.width ;
		_clip.y = ( f / cols ) * _clip.height;
	} //
	
	public void setFrameIndex( int x , int y ) { 
		int cols = cast(int)(_width  / _clip.width);
		int rows = cast(int)(_height / _clip.height);
		frameIndex = ( x + y * cols );
	} //

	public Rectangle clipRectangle(){
		return _clip;
	} //


	/**
	 * 生成
	 */
	private void create(SDL_Surface* s){
		uint id;
		glGenTextures( 1 , &id );
		glBindTexture(GL_TEXTURE_2D, id);
		gluBuild2DMipmaps(GL_TEXTURE_2D, 4, s.w, s.h, GL_RGBA, GL_UNSIGNED_BYTE, s.pixels);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		Console.writeln( "Create Texture ID:%d" , id );
		_id = id;
		_width   = s.w;
		_height  = s.h;
		_surface = s;
		_clip = new Rectangle( 0 , 0 , 1 , 1 );
		frameIndex = 0;
	} //

	/**
	 * (座標の色を取得)
	 */
	private Color getColor( SDL_Surface* s, int x , int y){
		Color ret;
		if ( ( x >= 0 && x < s.w ) && ( y >= 0 && y < s.h ) ){
			SDL_LockSurface(s);	
			 Uint32* surfacepixels = cast(Uint32*) s.pixels;
			 Uint32 c = surfacepixels[y * s.pitch / 4  + x];
			SDL_UnlockSurface(s);
			ret = Color.create(c);
		}else
			throw new Error("setColorKey error ");
		return ret;
	} //

	/**
	 * 抜き色設定
	 */
	private SDL_Surface* setColorKey( SDL_Surface* s , Color mask ){
		uint mColor = mask.color | 0xff000000u;
		Uint32* surfacepixels = cast(Uint32*) s.pixels;
		SDL_LockSurface(s);
		for( int y = 0 ; y < s.h; y++ ){
			for( int x = 0 ; x < s.w ; x++ ){
				Uint32* p = &(surfacepixels[y * s.pitch / 4  + x]);
				if (*p == mColor) *p = 0x00000000u;
			}
		}
		SDL_UnlockSurface(s);
		return s;
	} //
	

	private SDL_Surface* loadBitmap( string fileName ){
		SDL_Surface *s = SDL_LoadBMP(toStringz(fileName));
		if (!s) { throw new Error("Hell_Texture::loadBmp : not found file: " ~ fileName); }
		SDL_PixelFormat format;
		format.palette       = null;
		format.BitsPerPixel  = 32;
		format.BytesPerPixel = 4;
		format.Rmask         = 0x000000ff;
		format.Gmask         = 0x0000ff00;
		format.Bmask         = 0x00ff0000;
		format.Amask         = 0xff000000;
		format.Rshift        = 0;
		format.Gshift        = 8;
		format.Bshift        = 16;
		format.Ashift        = 24;
		format.Rloss         = 0;
		format.Gloss         = 0;
		format.Bloss         = 0;
		format.Aloss         = 0;
		format.alpha         = 0;
		SDL_Surface *ret = SDL_ConvertSurface(s, &format, SDL_SWSURFACE);
		SDL_FreeSurface(s);
		return ret;
	} //

	private static SDLTexture [ string ] pool;
	private static SDLTexture[] nokeys;
	private static int [ string ] refcnt;
	public static SDLTexture createTexture( string key , string fileName , bool share = true ){
		if ( !share ) {
			SDLTexture ret = new SDLTexture( fileName );
			nokeys ~= ret;
			return ret; 
		}
		key ~= fileName;
		if ( key in pool ) {
			refcnt[ key ]++;
			return cast(SDLTexture)pool[ key ].getClone();
		} else {
			SDLTexture ret = new SDLTexture( fileName );
			ret._key = key;
			refcnt[ key ] = 1;
			pool[ key ]   = ret;
			return ret;
		}
	} //

	public static SDLTexture createTexture( string key , string fileName , Color keyColor , bool share = true){
		if ( !share ) {
			SDLTexture ret = new SDLTexture( fileName , keyColor );
			nokeys ~= ret;
			return ret; 
		}

		key ~= fileName;
		if ( key in pool ) {
			refcnt[ key ]++;
			return cast(SDLTexture)pool[ key ].getClone();
		} else {
			SDLTexture ret = new SDLTexture( fileName , keyColor );
			ret._key = key;
			refcnt[ key ] = 1;
			pool[ key ]   = ret;
			return ret;
		}
	} //

	public static SDLTexture createTexture( string key , string fileName , int keyX , int keyY , bool share = true){
		if ( !share ) {
			SDLTexture ret = new SDLTexture( fileName , keyX , keyY );
			nokeys ~= ret;
			return ret; 
		}
		key ~= fileName;
		if ( key in pool ) {
			refcnt[ key ]++;
//			Console.writeln("refcnt %s = %d" , key , refcnt[ key ] );
			return cast(SDLTexture)pool[ key ].getClone();
		} else {
			SDLTexture ret = new SDLTexture( fileName , keyX , keyY );
			ret._key = key;
			refcnt[ key ] = 1;
			pool[ key ]   = ret;
			return ret;
		}
	} //
	
	public static void dispose(){
		foreach ( k ; pool.keys ) {
			SDLTexture tex = pool[k];
			pool.remove( k );
			refcnt.remove( k );
			glDeleteTextures( 1 , &tex._id );
			SDL_FreeSurface( tex._surface );
		}
//		foreach( SDLTexture tex ; nokeys ) {
//			glDeleteTextures( 1 , &tex._id );
//			SDL_FreeSurface( tex._surface );
//		}
	} //

	public static void dispose(string key){
		if ( key in pool ){
			refcnt[ key ]--;
			if ( refcnt[ key ] <= 0 ) {
				Console.writeln("DELETE Texture key:%s" , key );
				SDLTexture tex = pool[ key ];
				pool.remove( key );
				refcnt.remove( key );
				glDeleteTextures( 1 , &tex._id );
				SDL_FreeSurface( tex._surface );
			}
		}
	} //

} //

